<script>
export default {
  components: {},
  data () {
    return {
      radio: 0,
      activeName: '1',
    };
  },
  computed: {
    isButtonDisabled() {
      return this.radio === 0;
    }
  },
  methods: {
    check(radio) {
      console.log(radio)
      if (radio === 3) {
        this.$message.success('恭喜你，答对啦！')
      } else {
        this.$message.error('很遗憾，答错啦！')
      }
    },
  }
}
</script>

<template>
  <div>
    <div>
      <h1 align="center">2.4 ROP 防御技术</h1>
      <el-divider></el-divider>
      <h3>早期的防御技术</h3>
      前面我们已经学过各种 ROP 技术，但同时很多防御技术也被提出来，这一节我们就来看一下这些技术。
      <br>我们知道正常程序的指令流执行和 ROP 的指令流执行有很大不同，至少有下面两点：
      <ul>
        <li style="margin-left: 2em;">ROP 执行流会包含了很多 return 指令，而且之间只间隔了几条其他指令</li>
        <li style="margin-left: 2em;">ROP 利用 return 指令来 unwind 堆栈，却没有对应的 call 指令</li>
      </ul>
      以上面两点差异作为基础，研究人员提出了很多 ROP 检测和防御技术：
      <ul>
        <li style="margin-left: 2em;">针对第一点差异，可以检测程序执行中是否有频繁 return 的指令流，作为报警的依据</li>
        <li style="margin-left: 2em;">针对第二点差异，可以通过 call 和 return 指令来查找正常程序中通常都存在的后进先出栈里维护的不变量，判断其是否异常</li>
        <li style="margin-left: 2em;">还有更极端的，在编译器层面重写二进制文件，消除里面的 return 指令</li>
      </ul>
      所以其实这些早期的防御技术都默认了一个前提，即 ROP 中必定存在 return 指令。
      <br>另外对于重写二进制文件消除 return 指令的技术，根据二进制偏移也可能会得到攻击者需要的非预期指令，比如下面这段指令：
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="pln">b8 </span><span class="lit">13</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> </span><span class="lit">00</span><span class="pln">  mov $0x13</span><span class="pun">,</span><span class="pln"> </span><span class="pun">%</span><span class="pln">eax</span></code></li><li class="L1"><code class="lang-text"><span class="pln">e9 c3 f8 ff ff  jmp </span><span class="lit">3aae9</span></code></li></ol></pre>
      偏移两个十六进制得到下面这样：
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="lit">00</span><span class="pln"> </span><span class="lit">00</span><span class="pln">   add </span><span class="pun">%</span><span class="pln">al</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(%</span><span class="pln">eax</span><span class="pun">)</span></code></li><li class="L1"><code class="lang-text"><span class="lit">00</span><span class="pln"> e9   add </span><span class="pun">%</span><span class="pln">ch</span><span class="pun">,</span><span class="pln"> </span><span class="pun">%</span><span class="pln">cl</span></code></li><li class="L2"><code class="lang-text"><span class="pln">c3      ret</span></code></li></ol></pre>
      最终还是出现了 return 指令。
      <h3>没有 return 的 ROP</h3>
      后来又有人提出了不依赖于 return 指令的 ROP，使得早期的防御技术完全失效。return 指令的作用主要有两个：第一通过间接跳转改变
      <br>执行流，第二是更新寄存器状态。在 x86 和 ARM 中都存在一些指令序列，也能够完成这些工作，它们首先更新全局状态（如栈指针），
      <br>然后根据更新后的状态加载下一条指令序列的地址，最后跳转过去执行（把它叫做 update-load-branch 指令序列）。这样就避免的
      <br>return 指令的使用。
      <br>就像下面这样，x 代表任意的通用寄存器：
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="pln">pop x</span></code></li><li class="L1"><code class="lang-text"><span class="pln">jmp </span><span class="pun">*</span><span class="pln">x</span></code></li></ol></pre>
      r6 通用寄存器里是更新后的状态：
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="pln">adds r6</span><span class="pun">,</span><span class="pln"> </span><span class="com">#4</span></code></li><li class="L1"><code class="lang-text"><span class="pln">ldr r5</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[</span><span class="pln">r6</span><span class="pun">,</span><span class="pln"> </span><span class="com">#124]</span></code></li><li class="L2"><code class="lang-text"><span class="pln">blx r5</span></code></li></ol></pre>
      由于 update-load-branch 指令序列相比 return 指令更加稀少，所以需要把它作为 trampoline 重复利用。在构造 ROP 链时，选择以
      <br>trampoline 为目标的间接跳转指令结束的指令序列。当一个 gadget 执行结束后，跳转到 trampoline，trampoline 更新程序全局状态，
      <br>并将程序控制交给下一个 gadget，这样就形成了 ROP 链。
      <br>
      <el-image
          style="width: 640px; height: 398px"
          :src="require('@/assets/img/img35.png')">
      </el-image>

      <h3>参考资料</h3>
      <ul>
        <li style="margin-left: 2em;"><a href="https://www2.cs.uic.edu/~s/papers/noret_ccs2010/noret_ccs2010.pdf" target="_blank">Return-Oriented Programming without Returns</a></li>
        <li style="margin-left: 2em;"><a href="http://www.eit.lth.se/sprapport.php?uid=829" target="_blank">Analysis of Defenses against Return Oriented Programming</a></li>
      </ul>
      <el-divider></el-divider>

      <h3>以下哪个选项是用于防御 Return-Oriented Programming (ROP) 攻击的一种技术？</h3>
      <el-radio-group v-model="radio">
        <el-radio :label="1">XSS (Cross-Site Scripting)</el-radio>
        <el-radio :label="2">CSRF (Cross-Site Request Forgery)</el-radio>
        <el-radio :label="3">ASLR (Address Space Layout Randomization)</el-radio>
        <el-radio :label="4">SQL 注入 (SQL Injection)</el-radio>
        <el-button type="primary" plain :disabled="isButtonDisabled" @click="check(radio)">检查</el-button>
      </el-radio-group>
    </div>
    <el-divider></el-divider>

  </div>
</template>

<style scoped>
table {
  border-collapse: collapse;
  width: 100%;
}

th, td {
  border: 1px solid black;
  padding: 8px;
  text-align: left;
}
</style>